package com.bubblegumproject.ogo.tx;

import javax.persistence.EntityManager;

/**
 * Provides access and control to a ThreadLocal transaction.
 *
 * @author Azubuko Obele (buko.obele@gmail.com)
 */
public class Transaction {

    private static Factory factory;

    private static ThreadLocal<CurrentTransaction> threadLocal = new ThreadLocal<CurrentTransaction>();

    public static Factory getFactory() {
        return factory;
    }

    public static void setFactory(Factory factory) {
        Transaction.factory = factory;
    }

    public static EntityManager begin() {
        CurrentTransaction currentTx = threadLocal.get();

        if (currentTx == null) {
            currentTx = new CurrentTransaction(factory.createTransaction());
            currentTx.getEntityManager().getTransaction().begin();
            threadLocal.set(currentTx);
        }

        return currentTx.getEntityManager();
    }

    public static boolean isActive() {
        return threadLocal.get() != null && threadLocal.get().getEntityManager().getTransaction().isActive();
    }

    public static EntityManager current() {
        CurrentTransaction currentTx = threadLocal.get();
        if (currentTx != null) {
            return currentTx.getEntityManager();
        } else {
            throw new IllegalStateException("no transaction currently in progress");
        }
    }

    static CurrentTransaction getCurrentTransaction() {
        return threadLocal.get();
    }

    public static void flush() {
        EntityManager currentTx = current();
        currentTx.flush();
    }

    public static void commit() {
        EntityManager currentTx = current();
        currentTx.getTransaction().commit();
        currentTx.close();
        threadLocal.remove();
    }

    public static void rollback() {
        EntityManager currentTx = current();
        currentTx.getTransaction().rollback();
        currentTx.close();
        threadLocal.remove();
    }

    public static void cleanup() {
        threadLocal.remove();
    }

    /**
     * Factory for creating new transactions.
     */
    public static interface Factory {
        public EntityManager createTransaction();
    }
}
